package service

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"zimuzu_cvn_web_api/config"
	"zimuzu_cvn_web_api/lib/grpcClient"
	"zimuzu_cvn_web_api/model"
	. "zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"
)

//审核列表
func CvnExamineList(page, per, status int, keywords int64, minAmount, maxAmount float64) (data model.List, err error) {
	list, err := model.GetCvnExamineList(config.C.DB.DB, page, per, status, keywords,minAmount, maxAmount )
	if err != nil {
		err = errno.GetDataErr
		return data, err
	}
	countItem, err := model.GetCvnExamineListCount(config.C.DB.DB, status, keywords,minAmount, maxAmount )
	if err != nil {
		err = errno.GetDataErr
		return data, err
	}
	countPage := ListPage(countItem, per)
	data.CountItem = countItem
	data.CountPage = countPage
	data.List = list
	return data, nil
}

//检查审核项
func CvnExamineCheck(id int64) (data model.ExamineCheck, pass bool, err error) {
	var (
		signItem     model.ExamineCheckItem
		symbolItem   model.ExamineCheckItem
		rechargeItem model.ExamineCheckItem
	)
	examine, err := model.GetCvnExamine(config.C.DB.DB, id)
	if err != nil {
		err = errno.GetDataErr
		return data, false, err
	}
	logData, err := model.GetCvnLog(config.C.DB.DB, examine.LogId)
	if err != nil {
		err = errno.GetDataErr
		return data, false, err
	}
	if logData.Uid != examine.Uid {
		err = errno.DbDataError
		return data, false, err
	}
	if logData.Source != model.LogSourceOut && logData.Source != model.LogSourceInnerOut {
		err = errno.DbDataError
		return data, false, err
	}
	logList, err := model.GetCvnLogListByUid(config.C.DB.DB, logData.Uid)
	if err != nil {
		err = errno.GetDataErr
		return data, false, err
	}
	request := map[string]string{
		"uid": strconv.FormatInt(logData.Uid, 10),
	}
	//审核项：校验账户可用余额和冻结金额是否大于等于0
	amountData, err := model.GetCvnAmount(config.C.DB.DB, logData.Uid)
	if amountData.Balance >= 0 && amountData.FrozenBalance >= 0 {
		data.AmountBalance = true
	}
	//审核项：校验账户签名
	amountCheckResp, err := grpcClient.CvnAmountCheck(request)
	if err != nil {
		err = errno.GetDataErr
		return data, false, err
	}
	data.AmountSign.Ok = amountCheckResp.Ok
	data.AmountSign.OriginalSignString = amountData.SignString
	data.AmountSign.CorrectSignString = amountCheckResp.SignString
	//审核项：校验流水签名
	logListCheckResponse, err := grpcClient.CvnLogListCheck(request)
	if err != nil {
		err = errno.GetDataErr
		return data, false, err
	}
	if logListCheckResponse.ErrNum == 0 {
		data.LogSign.Ok = true
	}
	if len(logListCheckResponse.List) != len(logList) {
		err = errno.DbDataError
		return data, false, err
	}
	//审核项：校验流水表中amount字段求和后与账户表中balance字段是否相等
	logSum, err := model.SumCvnLogSource(config.C.DB.DB, logData.Uid, 0, 0)
	if err != nil {
		err = errno.GetDataErr
		return data, false, err
	}
	if FloatEqual(logSum, amountData.Balance, COIN_DECIMAL_CVNT+1) {
		data.Reconciliation = true
	}
	//迭代
	data.LogSourceSymbol.Ok = true
	data.RechargeExist.Ok = true
	for _, row := range logList {
		signItem.Id = row.Id
		signItem.Ok = logListCheckResponse.List[row.Id].Ok
		signItem.OriginalSignString = row.SignString
		signItem.CorrectSignString = logListCheckResponse.List[row.Id].SignString
		if signItem.CorrectSignString == "" {
			err = errno.DbDataError
			return data, false, err
		}
		data.LogSign.List = append(data.LogSign.List, signItem)
		//审核项：校验流水表中每条记录amount字段正负号
		ok := ExamineCvnLogSourceSymbol(row.Source, row.Amount)
		if !ok {
			data.LogSourceSymbol.Ok = false
		}
		symbolItem.Id = row.Id
		symbolItem.Ok = ok
		data.LogSourceSymbol.List = append(data.LogSourceSymbol.List, symbolItem)
		//审核项：校验日志表中每条充值记录是否在
		if row.Source == model.LogSourceIn {
			rechargeItem.Id = row.Id
			if strings.ToLower(row.RelateTable) == "cobo" { //调用支付网关接口：获取充值信息
				params := map[string]string{"id": row.RelateId}
				res, err := model.GatewayRequest("GET", ApiRechargeInfo, params, nil)
				if err != nil && res.Data.ErrorCode != 12004 {
					err = errno.GetDataErr
					return data, false, err
				}
				if res.Data.ErrorCode == 12004 {
					data.RechargeExist.Ok = false
					rechargeItem.Ok = false
				} else {
					rechargeItem.Ok = true
				}
			} else if strings.ToLower(row.RelateTable) == "eth_transactions" { //查询eth_transactions
				relateId, _ := strconv.ParseInt(row.RelateId, 10, 64)
				ok, err := model.ExistEthTransactions(config.C.DB.DB, relateId)
				if err != nil {
					err = errno.GetDataErr
					return data, false, err
				}
				if !ok {
					data.RechargeExist.Ok = false
					rechargeItem.Ok = false
				} else {
					rechargeItem.Ok = true
				}
			}
			data.RechargeExist.List = append(data.RechargeExist.List, rechargeItem)
		}
	}
	if data.AmountBalance && data.Reconciliation && data.AmountSign.Ok && data.LogSign.Ok && data.LogSourceSymbol.Ok && data.RechargeExist.Ok {
		pass = true
	}
	return data, pass, nil
}

//审核通过
func CvnExaminePass(id, operator int64) (err error) {
	var (
		updateLogData model.CvnLogDb
		post          = make(map[string]string)
	)
	examine, err := model.GetCvnExamine(config.C.DB.DB, id)
	if err != nil {
		err = errno.GetDataErr
		return err
	}
	if examine.Status != model.DealStatusCheck {
		err = errno.StatusError
		return err
	}
	logData, err := model.GetCvnLog(config.C.DB.DB, examine.LogId)
	if err != nil {
		err = errno.GetDataErr
		return err
	}
	if logData.Source != model.LogSourceOut && logData.Source != model.LogSourceInnerOut {
		err = errno.DbDataError
		return err
	}
	if logData.Status != model.DealStatusCheck {
		err = errno.DbDataError
		return err
	}
	_, ok, err := CvnExamineCheck(id)
	if err != nil {
		return err
	}
	if !ok {
		err = errno.ExamineCheckErr
		return err
	}
	data := model.CvnExamine{
		Id:       id,
		Operator: operator,
		Status:   model.DealStatusSuccess,
	}
	amount := math.Abs(logData.Amount)
	if logData.Source == model.LogSourceInnerOut {
		relateId := strconv.FormatInt(examine.LogId, 10)
		exist, err := model.ExistCvnLogRelated(config.C.DB.DB, relateId, model.LogSourceInnerIn)
		if err != nil {
			err = errno.GetDataErr
			return err
		}
		toUser, _, err := GetCheckAddress(logData.To)
		if err != nil {
			err = errno.GetDataErr
			return err
		}
		amountData := UpdateCvnAmountParams{
			Uid:         toUser.Uid,
			Amount:      amount,
			Source:      model.LogSourceInnerIn,
			RelateId:    strconv.FormatInt(logData.Id, 10),
			RelateTable: TableCvnLog,
			From:        logData.From,
			To:          logData.To,
		}
		//开启事务
		tx, err := config.C.DB.DB.Beginx()
		if err != nil {
			err = errno.UpdateDataErr
			return err
		}
		//修改审核状态
		err = model.UpdateCvnExamine(tx, data)
		if err != nil {
			_ = tx.Rollback()
			err = errno.UpdateDataErr
			return err
		}
		//修改流水状态
		updateLogData.Id = logData.Id
		updateLogData.Status = model.DealStatusSuccess
		err = model.UpdateCvnLogStatus(tx, updateLogData)
		if err != nil {
			_ = tx.Rollback()
			err = errno.UpdateDataErr
			return err
		}
		//收款账户收款
		if !exist {
			_, err = UpdateCvnAmountBalance(tx, amountData)
			if err != nil {
				_ = tx.Rollback()
				return err
			}
		}
		//提交事务
		if err = tx.Commit(); err != nil {
			err = errno.UpdateDataErr
			return err
		}
	} else if logData.Source == model.LogSourceOut {
		//修改审核状态
		err = model.UpdateCvnExamine(config.C.DB.DB, data)
		if err != nil {
			err = errno.UpdateDataErr
			return err
		}
		post["amount"] = fmt.Sprintf("%.0f", amount*math.Pow(10, COIN_DECIMAL_CVNT))
		post["coin"] = COIN_NAME_CVNT
		post["address"] = logData.To
		post["requestId"] = COIN_NAME_CVNT + "_" + strconv.FormatInt(logData.Id, 10)
		_, _ = model.GatewayRequest("POST", ApiTransfer, post, nil)
	}
	return nil
}

//审核不通过
func CvnExamineRefuse(id, operator int64) (err error) {
	examine, err := model.GetCvnExamine(config.C.DB.DB, id)
	if err != nil {
		err = errno.GetDataErr
		return err
	}
	if examine.Status != model.DealStatusCheck {
		err = errno.StatusError
		return err
	}
	logData, err := model.GetCvnLog(config.C.DB.DB, examine.LogId)
	if err != nil {
		err = errno.GetDataErr
		return err
	}
	data := model.CvnExamine{
		Id:       id,
		Operator: operator,
		Status:   model.DealStatusFail,
	}
	ok := CvnTransferFailed(logData)
	if !ok {
		err = errno.UpdateDataErr
		return err
	}
	err = model.UpdateCvnExamine(config.C.DB.DB, data)
	if err != nil {
		err = errno.UpdateDataErr
		return err
	}
	return nil
}
